package org.example.queueadmin.log;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.queueadmin.config.SystemConfigService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

@Service
@RequiredArgsConstructor
@Slf4j
public class MessageLogService {

    private final MessageLogRepository repository;
    private final SystemConfigService configService;
    
    @Async
    public CompletableFuture<Void> logMessage(Long taskId, String direction, String source, String target,
                                            byte[] messageBody, boolean success, String errorMessage) {
        try {
            MessageLog logEntry = new MessageLog();
            logEntry.setTaskId(taskId);
            logEntry.setTimestamp(Instant.now());
            logEntry.setLevel(success ? MessageLog.LogLevel.INFO : MessageLog.LogLevel.ERROR);
            logEntry.setDirection(direction);
            logEntry.setSource(source);
            logEntry.setTarget(target);
            logEntry.setSuccess(success);
            logEntry.setErrorMessage(errorMessage);

            // 安全地处理消息内容
            if (messageBody != null && messageBody.length > 0) {
                String preview = createSafeMessagePreview(messageBody);
                logEntry.setMessagePreview(preview);
                // 保存完整消息内容
                logEntry.setMessageBody(messageBody);
            }

            repository.save(logEntry);
        } catch (Exception e) {
            log.warn("Failed to log message for task {}: {}", taskId, e.getMessage());
        }
        return CompletableFuture.completedFuture(null);
    }

    private String createSafeMessagePreview(byte[] messageBody) {
        try {
            // 从配置获取最大长度
            int maxLength = configService.getConfigValueAsInt("message.preview.max.length", 200);
            int hexLimit = configService.getConfigValueAsInt("message.preview.hex.limit", 50);
            int previewLength = Math.min(messageBody.length, maxLength);

            // 尝试不同的编码方式
            String preview = null;

            // 1. 尝试UTF-8
            try {
                preview = new String(messageBody, 0, previewLength, "UTF-8");
                if (isValidText(preview)) {
                    return sanitizeText(preview);
                }
            } catch (Exception ignored) {}

            // 2. 尝试检测JSON
            try {
                String jsonTest = new String(messageBody, 0, Math.min(messageBody.length, 1000), "UTF-8");
                if (jsonTest.trim().startsWith("{") || jsonTest.trim().startsWith("[")) {
                    return sanitizeText(jsonTest.substring(0, Math.min(jsonTest.length(), maxLength)));
                }
            } catch (Exception ignored) {}

            // 3. 如果都不行，显示十六进制
            StringBuilder hex = new StringBuilder();
            for (int i = 0; i < Math.min(messageBody.length, hexLimit); i++) {
                hex.append(String.format("%02X ", messageBody[i]));
            }
            return "[HEX] " + hex.toString().trim() + (messageBody.length > hexLimit ? "..." : "");

        } catch (Exception e) {
            return "[ERROR] Failed to preview message: " + e.getMessage();
        }
    }

    private boolean isValidText(String text) {
        // 检查是否包含太多控制字符
        long controlChars = text.chars().filter(c -> Character.isISOControl(c) && c != '\n' && c != '\r' && c != '\t').count();
        return controlChars < text.length() * 0.1; // 控制字符不超过10%
    }

    private String sanitizeText(String text) {
        // 移除危险的控制字符，保留常见的换行符
        return text.replaceAll("[\\p{Cntrl}&&[^\r\n\t]]", "�")
                  .replaceAll("[\r\n]+", " ") // 将换行符替换为空格
                  .trim();
    }
    
    public Page<MessageLog> getLogs(Long taskId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return repository.findByTaskIdOrderByTimestampDesc(taskId, pageable);
    }
    
    public Page<MessageLog> getErrorLogs(Long taskId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        return repository.findByTaskIdAndLevelOrderByTimestampDesc(taskId, MessageLog.LogLevel.ERROR, pageable);
    }
    
    // 根据配置清理旧日志
    @Scheduled(fixedRateString = "#{${log.cleanup.interval.hours:1} * 3600000}")
    @Transactional
    public void cleanupOldLogs() {
        try {
            // 检查是否启用清理
            boolean enabled = configService.getConfigValueAsBoolean("log.cleanup.enabled", true);
            if (!enabled) {
                return;
            }

            // 获取保留天数
            int retentionDays = configService.getConfigValueAsInt("log.cleanup.retention.days", 7);
            int batchSize = configService.getConfigValueAsInt("log.cleanup.batch.size", 1000);

            Instant cutoff = Instant.now().minus(retentionDays, ChronoUnit.DAYS);
            int deleted = repository.deleteOldLogs(cutoff);

            if (deleted > 0) {
                log.info("Cleaned up {} old message logs (retention: {} days)", deleted, retentionDays);
            }
        } catch (Exception e) {
            log.error("Failed to cleanup old logs: {}", e.getMessage(), e);
        }
    }

    public Optional<MessageLogController.MessageDetail> getMessageDetail(Long id) {
        return repository.findById(id).map(messageLog -> {
            String fullContent;
            try {
                if (messageLog.getMessageBody() != null && messageLog.getMessageBody().length > 0) {
                    // 尝试解码完整消息内容
                    fullContent = new String(messageLog.getMessageBody(), "UTF-8");
                } else if (messageLog.getMessagePreview() != null && !messageLog.getMessagePreview().isEmpty()) {
                    // 如果没有完整消息体，使用预览内容（可能被截断）
                    fullContent = messageLog.getMessagePreview();
                    if (messageLog.getMessagePreview().length() >= 500) {
                        fullContent += "\n\n[注意: 这是截断的预览内容，完整消息内容未存储]";
                    }
                } else {
                    fullContent = "消息内容为空";
                }
            } catch (Exception e) {
                // 如果解码失败，显示十六进制
                StringBuilder hex = new StringBuilder();
                byte[] body = messageLog.getMessageBody();
                if (body != null) {
                    for (int i = 0; i < Math.min(body.length, 1000); i++) {
                        hex.append(String.format("%02X ", body[i]));
                        if (i % 16 == 15) hex.append("\n");
                    }
                    if (body.length > 1000) {
                        hex.append("\n... (truncated)");
                    }
                    fullContent = "[HEX]\n" + hex.toString();
                } else {
                    fullContent = "解码失败: " + e.getMessage();
                }
            }

            return new MessageLogController.MessageDetail(
                messageLog.getId(),
                messageLog.getTimestamp().toString(),
                messageLog.getDirection(),
                messageLog.getSource(),
                messageLog.getTarget(),
                messageLog.getSuccess(),
                messageLog.getErrorMessage(),
                fullContent
            );
        });
    }
    
    public long getSuccessCount(Long taskId) {
        return repository.countSuccessfulMessages(taskId);
    }
    
    public long getFailureCount(Long taskId) {
        return repository.countFailedMessages(taskId);
    }
}
